library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use work.dec_pkg.all;
entity top_control is
port (
		rst1 : in std_ulogic;
                clk_l : in std_ulogic ;
                clk_h : in std_ulogic;
                sig : out word16;
               -- sel : out std_ulogic;
                cal_len : out frame_length;
                dec_state : in std_ulogic;
                dec_ack : in std_ulogic;
                m1_flag : out std_ulogic;
                m2_flag : out std_ulogic;
                dec_req : out std_ulogic;
                dec_end : in std_ulogic;
                din_addr : out word9;
                 irq2 : out std_ulogic;
                wr_en :   out std_ulogic_vector(7 downto 0);
                rd_en : out std_ulogic_vector(7 downto 0);
                addr1 : in std_ulogic_vector(15 downto 0);
                cmd1 : in std_ulogic;
                m1_en :in std_ulogic;
                ack12 : out std_ulogic;
                data1 : in word32;
                data13 : out word32;
                addr2 : in std_ulogic_vector(15 downto 0);
                m2_en : in std_ulogic;
                cmd2 : in std_ulogic;
                ack22 : out  std_ulogic;
                wb_clk : in std_ulogic;
                wb_en : in std_ulogic;
                wb_addr : in word16;
                wb_data : in word16;
                dout_addr : out word9;
                dout_0 : in word16;
                dout_1 : in word16;
                dout_2 : in word16;
                dout_3 : in word16;
                dout_4 : in word16;
                dout_5 : in word16;
                dout_6 : in word16;
                dout_7 : in word16;
                data2  : out word16 ;
                BP : in std_ulogic;
                 lkp    : in std_ulogic;
			           LKDT   : out std_ulogic;
			           rst0   : out std_ulogic
);
end entity ;
architecture rtl of top_control is
signal  w_num,r_num:bank_num ; -- determin which bank is used
signal r_num_temp ,r_num_temp2 ,r_num_temp3,r_num_temp4 :bank_num;
signal f_len : frame_length;
signal b_len : block_length;
signal read_en,sel :std_ulogic;
--signal din_addr : word9;
type fsm_inout is(s0,s1,s2,s3);
signal sig0,sig1	: word16;
signal cal_len0,cal_len1:frame_length;
signal c_state_in ,n_state_in , c_state_out,n_state_out :fsm_inout;
signal temp,temp3,temp4 : std_ulogic_vector(12 downto 0);
signal temp2 ,temp5,temp6:std_ulogic_vector(11 downto 0);
signal temp_en1,temp_en2,temp_en3,temp_en4:std_ulogic;
signal temp_en11 ,temp_en12,temp_en13,temp_en14:std_ulogic;
signal m1_flag_temp ,m2_flag_temp,m1_flag_temp2:std_ulogic ;
signal temp_data,temp_data1 : word32;
signal temp_out : word16;
signal irq ,ack1,ack2,rst :std_ulogic;
signal din_addr_temp , dout_addr_temp,din_addr_temp2,dout_addr_temp2,din_addr_temp3,dout_addr_temp3 : std_ulogic_vector(7 downto 0);
signal wr_en_temp ,wr_en_temp2,wr_en_temp3:   std_ulogic_vector(7 downto 0);
signal rd_en_temp ,rd_en_temp2,rd_en_temp3: std_ulogic_vector(7 downto 0);
signal dout_0_temp,dout_1_temp,dout_2_temp,dout_3_temp,dout_4_temp,dout_5_temp,dout_6_temp,dout_7_temp : word16;
signal dout_0_temp2,dout_1_temp2,dout_2_temp2,dout_3_temp2,dout_4_temp2,dout_5_temp2,dout_6_temp2,dout_7_temp2 : word16;
signal data12:word32;
signal m1_flag2,m1_flag3: std_ulogic;
signal m2_flag2,m2_flag3: std_ulogic;
signal addr2_temp ,addr2_temp1 :std_ulogic_vector(11 downto 0);
signal data14 : std_ulogic_vector(31 downto 0);
signal wb_en1 :  std_ulogic;
signal wb_addr1 :  word16;
signal wb_data1 :  word16;

begin 
  process (wb_clk)
    begin 
      if wb_clk'event and wb_clk = '1' then 
        wb_en1 <= wb_en;
        wb_addr1 <= wb_addr;
        wb_data1 <= wb_data;
      end if;
    end process;

LKDT <= lkp;
rst0 <= rst;
rst  <= (not BP) and  lkp  and rst1;
	process (clk_h,rst)
	begin 
		if rst = '0' then 
                       irq2 <= '0';
		       ack12 <= '0';
		       ack22 <= '0';
		elsif clk_h'event and clk_h = '1' then 
			irq2 <= irq ;
			ack12 <= ack1;
			ack22 <= ack2;
		end if;
	end process;
		
		process(r_num_temp3, dout_0, dout_1, dout_2 ,dout_3, dout_4, dout_5, dout_6 ,dout_7 )
		  begin 
		    case r_num_temp3 is 
	         when 0 =>  temp_out <= dout_0;
	         when 1 =>  temp_out <= dout_1;
	         when 2 =>  temp_out <= dout_2;
	         when 3 =>  temp_out <= dout_3;
	         when 4 =>  temp_out <= dout_4;
 		       when 5 =>  temp_out <= dout_5;
		       when 6 =>  temp_out <= dout_6;
		       when 7 =>  temp_out <= dout_7;
		       when others => temp_out <= (others => '0');
		       end case ;
		end process ; 
      process(clk_l)
       variable s_bit :std_ulogic;
       
       begin
         if clk_l'event and clk_l = '1' then 
          s_bit := transform(temp_out);
            if m2_en = '1' then 
         if sel = '0' then 
	              data2 <= temp_out;
	        else
	              data2 <= "000000000000000"&s_bit ;
	       end if;
	       else 
	         data2 <= (others => '0');
	         end if;
	         end if;
	       end process;



         m1_flag <= m1_flag_temp;
	       m2_flag <= m2_flag_temp;
         wr_en_temp3 <= sel_bank(addr1(11 downto 0),b_len);   -- l,wb -> l
         din_addr_temp <= bank_addr(addr1(11 downto 0),b_len,wr_en_temp3); -- l ,wb ,l -> l
		     din_addr <= m1_flag3&din_addr_temp3; -- l ,l --> l
		     process(rd_en_temp3)--l  -->l
		       begin 
		         if rd_en_temp3(0) = '1' then 
		             r_num <= 0;
		         elsif rd_en_temp3(1) = '1' then 
		            r_num <= 1;
		         elsif rd_en_temp3(2) = '1' then 
		            r_num <= 2;
		         elsif rd_en_temp3(3) = '1' then 
		              r_num <= 3;
		         elsif rd_en_temp3(4) = '1' then 
		              r_num <= 4;
		         elsif rd_en_temp3(5) = '1' then 
		               r_num <= 5;
		        elsif rd_en_temp3(6) = '1' then 
		               r_num <= 6;
		         elsif rd_en_temp3(7) = '1' then 
		               r_num <= 7;
		         else
		               r_num <= 7;
		         end if;
	     end process ;
	      
	      
	      
	      process (clk_l)
	      begin 
	      if clk_l'event and clk_l = '1' then 
	           r_num_temp <= r_num;  ---  l-->l
	           end if;
	       end process ;	              
		     process(clk_l,rst)  --    h -> l  
		       begin
		         if rst = '0' then 
		             data12 <= (others => '0');
		             wr_en_temp2 <= (others => '0');
		             rd_en_temp2 <= (others => '0');
		             r_num_temp2 <= 0;
		             m1_flag2 <= '0';
		             din_addr_temp2 <= (others => '0');             
                 m2_flag2 <= '0';
                 dout_addr_temp2 <= (others => '0');  
		         elsif clk_l'event and clk_l = '1' then
		             m1_flag2 <= m1_flag_temp;  -- h - > l
		             m2_flag2 <= m2_flag_temp;  -- h - > l
		             wr_en_temp2 <= wr_en_temp3;-- l --> l
		             rd_en_temp2 <= rd_en_temp3;-- l --> l
		             r_num_temp2 <= r_num_temp; -- l --> l 
		             data12 <= data1;          -- l  -->l
		             din_addr_temp2 <= din_addr_temp; ---l -->l
		             dout_addr_temp2 <= dout_addr_temp; --l --> l
		             end if;
		             end process ;
		         process(clk_l,rst)   --l -->l
		       begin
		         if rst = '0' then
		             
		             wr_en   <= (others => '0');
		             rd_en  <=  (others => '0');
		             data14 <= (others => '0');
		             r_num_temp3 <= 0;
		             din_addr_temp3 <= (others => '0');
		             m1_flag3 <= '0';
		             dout_addr_temp3 <= (others => '0');
		             m2_flag3 <= '0';
		              		            
		         
		        elsif clk_l'event and clk_l = '1' then
		             din_addr_temp3 <= din_addr_temp2;
		             dout_addr_temp3 <= dout_addr_temp2;
		             wr_en <= wr_en_temp2;
		             rd_en <= rd_en_temp2;
		             r_num_temp3 <= r_num_temp2;
		             m1_flag3 <= m1_flag2;
		             m2_flag3 <= m2_flag2 ;
		             data13 <= data12;
		          end if;
		          end process ;
		         -- process (clk_l)
		           -- begin 
		             -- if clk_l'event and clk_l = '1' then 
		               --      data13 <= data14;
		               -- end if;
		              -- end process ;
		           
          p1:process(clk_h, rst)
		  begin
		   if rst='0' then
	              c_state_in <= s0;
                   elsif rising_edge(clk_h) then
		       c_state_in <= n_state_in;					      	    
		       end if;		
		   end process;
							 temp <= addr1(12 downto 0);
				process(clk_h)-- avoid metastable state
		   begin 
			 if clk_h'event and clk_h = '1' then 
       temp3 <= temp ;  --l -- > h
	     temp_en1 <= m1_en; -- l --> h
			 temp_en2 <= cmd1 ; -- l -->h
			 temp_data <= data1;-- l->h
		
	            end if;
		         end process ;
						            
			 process (clk_h)-- avoid metastable state
			 begin 									         
			 if clk_h'event and clk_h = '1' then 
			  temp4 <= temp3;						                  
			  temp_en3 <= temp_en1;
		    temp_en4 <= temp_en2;
		    temp_data1 <= temp_data;
			 end if;
		         end process;
																	           
            process(clk_h,rst)
	           begin
		        if rst = '0' then m1_flag_temp <= '0';
		        elsif clk_h'event and clk_h = '1' then 
		        if dec_state = '0' and dec_ack = '1' then					      
		                   m1_flag_temp <= not m1_flag_temp;
		         else 
	                      m1_flag_temp <= m1_flag_temp;
							end if;								                
							end if;
	            end process;
					 p2:process(c_state_in,temp_en3,temp_en4,temp,w_num,f_len,dec_state,dec_ack,temp4,dec_end)
		 variable addr: integer;
	   begin
	          addr := to_int(temp4);
	          n_state_in <= c_state_in;
	          case c_state_in is
		  when s0  => ack1  	<='0';   --initial state  ,if m1_en = '1' and cmd = '1'  begin  write data to ram 
                   dec_req	<='0';
		                            
		       if (temp_en3='1') and (temp_en4='1') then 				   
		        n_state_in 	<= s1; 
	           else							                        
	           n_state_in 	<= s0; 
		   end if;
		   when s1  => ack1   	<= '1';			-- input u and chanx
		               dec_req	<= '0';					                           
		               if  addr=(f_len)   then  --when ram is full then change the state 
			        n_state_in <=s2;
													    end if;																	
				when s2  => dec_req	<='1';
			            
			             ack1 <= '0';
		               if dec_state = '0' and dec_ack = '1' then	--here look out the conformity of two signals
			                 dec_req	<='0';
                       n_state_in	<=s3;
		                 end if;
		    when s3  => ack1		<='0';			-- wait for next frame from CPU
			              dec_req	<='0';
		              
		            if (temp_en3='1')and (temp_en4 = '1') and addr = 0 then 
			              n_state_in <=s1;
			         else
			              n_state_in <=s3;
			   end if;				
			   end case;
		 end process;								    
		 
		 sig <= sig0 when m1_flag_temp='0' else sig1;
		 cal_len <= cal_len0 when m1_flag_temp='0' else cal_len1;			    
		 sig_regs:process(rst, clk_h,temp4)
			  variable addr: integer ;
			  begin
		          addr := to_int(temp4);
			  if rst='0' then
			   sig0	<= (others=>'0');
			   sig1	<= (others=>'0');						      
			    cal_len0 <= 0;
	        cal_len1 <= 0;							       
	        elsif rising_edge(clk_h) then
			   if addr=f_len  then							      
			    if m1_flag_temp='0' then							   
			    sig0 <= sig_value(temp_data1(15 downto 0));
			    cal_len0 <= to_int(temp_data1(31 downto 16));				     
			     else									   
			     sig1 <= sig_value(temp_data1(15 downto 0));
			     cal_len1 <= to_int(temp_data1(31 downto 16));				      
			      end if;
			   end if;
			   end if;
			   end process;								 --state of machine for controlling the output of decoded data
			 rd_en_temp3 <= sel_bank(addr2(11 downto 0), b_len);				           --determine which memory among eight ones
	     dout_addr  <= (not m2_flag3) & dout_addr_temp3;
	     dout_addr_temp <= bank_addr(addr2(11 downto 0),b_len,rd_en_temp3);			
	     
	     
		    
		 p3:process(clk_h, rst)
		  begin
		  if rst='0' then
		           c_state_out <= s0;
	          elsif rising_edge(clk_h) then
		           c_state_out <= n_state_out;
		       end if;
	         end process;
	          
								   process(clk_h,rst)
	           begin 
		              if rst = '0' then 
			           m2_flag_temp <= '0';
			      elsif clk_h'event and clk_h = '1' then 
			           if dec_end = '1' then 
				    m2_flag_temp <= not m2_flag_temp;
	                             end if;
			       end if;
		 end process;
		 temp2 <= addr2(11 downto 0);
		  process (clk_h)
	     begin 
		   if clk_h'event and clk_h = '1' then 
	        temp5 <= temp2;
		      temp_en11 <= m2_en;
		      temp_en12 <= cmd2;						      
		       end if;
	         end process ;								      
	         process (clk_h)
	              begin 
		    if clk_h'event and clk_h = '1' then 
	             temp6 <= temp5;
		        temp_en13 <= temp_en11;						            
		        temp_en14 <= temp_en12;
		      end if;
		  end process;
			
p4:process(c_state_out,addr2,temp_en13,temp_en14,temp6,dec_end,r_num,f_len)
              variable addr: integer ;
	       begin
	       addr := to_int(temp6); 
	       n_state_out <= c_state_out;
	       case c_state_out is
	       when s0  => ack2  	<='0';
	                  -- read_en  	<= '0';							 
	            if (dec_end='1') then 					-- wait for the end of 1st frame
		      n_state_out <= s1;  irq	<='1';						 
		      else 
		      n_state_out <= s0;  irq	<='0';
		      end if;
	        when
	         s1  => ack2	<='0';
			 --    read_en  	<= '0';
			     if (temp_en13 = '1')and(temp_en14 = '1') then 	
			     n_state_out <= s2; irq	<= '0'; 
			     else
			      n_state_out <= s1; irq	<= '1';						      
			      end if;
							when s2  => ack2	 	<='1';	
			       irq		<='0';	      
			   --    read_en  	<= '1';							   
			       if (addr=f_len) then				-- here look out the conformity of two signals
			      n_state_out <= s3;
				 end if;
		 when s3  => ack2		<='0';    			  -- wait for next frame from CPU
		              irq		<='0'; 
			 --      read_en  	<= '0';
                              if (dec_end='1') then 							         n_state_out <=s1;		
			      else
				     n_state_out <=s3;
				 end if;
			end case;
		 end process;		
		 
		 
		 																
		 process (wb_clk,wb_en1)
	        begin 
		if wb_en1 = '1' then 
	        if wb_clk'event and wb_clk = '1' then 
		if wb_addr1 = "1000000000000000" then 
	          b_len <= to_int(wb_data1(15 downto 0));
		elsif wb_addr1 = "1000000000000001" then
	       	f_len <= to_int(wb_data1(15 downto 0));
               elsif wb_addr1 = "1000000000000010"  then 
		   sel <= wb_data1(0);
		end if;
	   end if;
		 end if;
		end process;
end rtl;
